REMEZ |
| REMEZ is a library that allows designing: Low Pass, Band Pass, High Pass, Hilbert and Differentiator filters. The REMEZ library is based on the Parks-McClellan algorithm, see Discrete-Time Signal Processing (Alan V. Oppenheim and Ronal W. Schafer). REMEZ es una librería que permite diseñar filtros: Pasa Baja, Pasa Banda, Pasa Alta, de Hilbert y Diferenciadores. La librería de REMEZ está basa en el algoritmo de Parks-McClellan, vea Discrete-Time Signal Processing (Alan V. Oppenheim and Ronal W. Schafer). |
| Problem 1 |
| Create a project called RemezTest to create to design filters using the REMEZ algorithm. The program must display the Impulse and Frequency Response. Use a slider to control the length of the filter. Cree un proyecto llamado RemezTest para filtros usando el algoritmo de REMEZ. El programa debe mostrar la respuesta al impulso y la respuesta en frecuencia. Use un slider para la longitud del filtro. |
| Solution A |
| Create a Wintempla Dialog Application. Using Wintempla create the GUI shown below. After inserting the slider for the length of the filter, double click the control and mark the HSCROLL event. Cree una aplicación de Diálogo de Wintempla. Use Wintempla para la crear la GUI mostrada debajo. Después de insertar el slider para la longitud del filtro, haga doble clic en el control para marcar el evento de HSCROLL. |

| Solution B |
| Edit the RemezTest.h file as shown. Edite el archivo RemezTest.h como se muestra. |
| RemezTest.h |
| #pragma once //______________________________________ RemezTest.h #include "resource.h" class RemezTest: public Win::Dialog { public: RemezTest() { } ~RemezTest() { } Math::Remez remez; const size_t numPoints = 2048; valarray<double> freqRad; void UpdateGraphs(); protected: . . . }; |
| Solution C |
| Edit the RemezTest.cpp file as shown. Edite el archivo RemezTest.cpp como se muestra. |
| RemezTest.Cpp |
| . . . void RemezTest::Window_Open(Win::Event& e) { //________________________________________________________ sldLength sldLength.SetRange(2, 100); sldLength.Position = 55; tbxLength.IntValue = 55; //________________________________________________________ xyFreqResp xyFreqResp.CaptionX = L"Frequency (radians)"; xyFreqResp.CaptionY = L"|H[f]| dB"; xyFreqResp.MinX= 0.0; // rads xyFreqResp.MaxX = 3.2; // rads xyFreqResp.MinY= -100.0; // dB xyFreqResp.MaxY= 10.0; // dB xyFreqResp.DivisionCountX = 16; xyFreqResp.DivisionCountY = 11; xyFreqResp.SubDivisionCountX = 0; xyFreqResp.ColorMode = WIN_COLOR_MODE_DARK; xyFreqResp.TextColor = RGB(180, 180, 190); xyFreqResp.Graphs.Add(numPoints); freqRad.resize(numPoints); const double deltaFreq = M_PI / (numPoints - 1); for (int i = 0; i < numPoints; i++) { freqRad[i] = i * deltaFreq; xyFreqResp.Graphs[0][i].x = i * deltaFreq; xyFreqResp.Graphs[0][i].y = -200.0; } xyFreqResp.Graphs[0].Color = RGB(0, 255, 0); //________________________________________________________ xyImpulseResponse xyImpulseResponse.CaptionX = L"n"; xyImpulseResponse.CaptionY = L"h[n]"; xyImpulseResponse.MinX= -1.0; xyImpulseResponse.MaxX= 6.28; xyImpulseResponse.MinY= -0.7; xyImpulseResponse.MaxY= 0.7; xyImpulseResponse.DivisionCountY = 7; xyImpulseResponse.ColorMode = WIN_COLOR_MODE_DARK; xyImpulseResponse.TextColor = RGB(180, 180, 190); xyImpulseResponse.Graphs.Add(); xyImpulseResponse.Graphs[0].Type = Win::Graph::impulse; xyImpulseResponse.Graphs[0].Color = RGB(0, 255,0); // radioLowPass.Checked = true; UpdateGraphs(); } void RemezTest::UpdateGraphs() { Win::HourGlassCursor hgc(true); const int length = tbxLength.IntValue; vector<Math::Remez::Band> bands; Math::Remez::Band band; valarray<double> h; valarray<double> freq; valarray<double> errorData; double error = 0.0; if (radioLowPass.Checked) { //_________________________________________________________ 1. LowPass band.w1 = 0.0; // rads band.w2 = 0.628; // rads band.priority = 0.1; // from 0 to 1 band.gain = 1.0; // from 0 to 1 bands.push_back(band); // band.w1 = 0.942; // rads band.w2 = M_PI; // rads band.priority = 1.0; // from 0 to 1 band.gain = 0.0; // from 0 to 1 bands.push_back(band); // error = remez.ComputeImpulseResponse(bands, length, h); } else if (radioHighPass.Checked) { //_________________________________________________________ 2. HighPass band.w1 = 0.0; // rads band.w2 = 0.628; // rads band.priority = 1.0; // from 0 to 1 band.gain = 0.0; // from 0 to 1 bands.push_back(band); // band.w1 = 0.942; // rads band.w2 = M_PI; // rads band.priority = 0.1; // from 0 to 1 band.gain = 1.0; // from 0 to 1 bands.push_back(band); // error = remez.ComputeImpulseResponse(bands, length, h); } else if (radioBandPass.Checked) { //_________________________________________________________ 3. BandPass band.w1 = 0.0; // rads band.w2 = 0.628; // rads band.priority = 1.0; // from 0 to 1 band.gain = 0.0; // from 0 to 1 bands.push_back(band); // band.w1 = 1.257; // rads band.w2 = 2.199; // rads band.priority = 0.1; // from 0 to 1 band.gain = 1.0; // from 0 to 1 bands.push_back(band); // band.w1 = 2.670; // rads band.w2 = M_PI; // rads band.priority = 1.0; // from 0 to 1 band.gain = 0.0; // from 0 to 1 bands.push_back(band); // error = remez.ComputeImpulseResponse(bands, length, h); } else if (radioBandStop.Checked) { //_________________________________________________________ 4. BandStop band.w1 = 0.0; // rads band.w2 = 0.628; // rads band.priority = 0.1; // from 0 to 1 band.gain = 1.0; // from 0 to 1 bands.push_back(band); // band.w1 = 1.257; // rads band.w2 = 2.199; // rads band.priority = 1.0; // from 0 to 1 band.gain = 0.0; // from 0 to 1 bands.push_back(band); // band.w1 = 2.670; // rads band.w2 = M_PI; // rads band.priority = 0.1; // from 0 to 1 band.gain = 1.0; // from 0 to 1 bands.push_back(band); // error = remez.ComputeImpulseResponse(bands, length, h); } else if (radioHilbert.Checked) { //_________________________________________________________ 5. Hilbert Transform band.w1 = 0.314; // rads band.w2 = 2.83; // rads band.priority = 1.0; // from 0 to 1 band.gain = 1.0; // from 0 to 1 bands.push_back(band); error = remez.ComputeHilbertImpulseResponse(bands, length, h); } else if (radioDifferentiator.Checked) { //_________________________________________________________ 6. Differentiator band.w1 = 0.0; // rads band.w2 = 2.6; // rads band.priority = 1.0; // from 0 to 1 band.gain = 1.0; // from 0 to 1 bands.push_back(band); // band.w1 = 2.9; // rads band.w2 = M_PI; // rads band.priority = 1.0; // from 0 to 1 band.gain = 0.0; // from 0 to 1 bands.push_back(band); error = remez.ComputeDifferentiatorImpulseResponse(bands, length, h); } //___________________________________________________________ 7. xyImpulseResponse const size_t len = h.size(); int i; xyImpulseResponse.Graphs[0].SetPointCount(len); for(i = 0; i < (int)len; i++) { xyImpulseResponse.Graphs[0][i].x = i; xyImpulseResponse.Graphs[0][i].y = h[i]; } xyImpulseResponse.MaxX= (int)len; xyImpulseResponse.RefreshAll(); //___________________________________________________________ 8. xyFreqResp valarray<complex<double> > H; // H(exp(jw)) Math::FIRFilter filter; filter.Create(h); filter.GetFrequencyResponse(freqRad, H); if (radioDifferentiator.Checked) { xyFreqResp.MinY = 0.0; xyFreqResp.MaxY = 3.0; xyFreqResp.DivisionCountY = 3; for (i = 0; i < (int)numPoints; i++) { xyFreqResp.Graphs[0][i].y = abs(H[i]); } } else { xyFreqResp.MinY = -100.0; // dB xyFreqResp.MaxY = 10.0; // dB xyFreqResp.DivisionCountY = 11; for (i = 0; i < (int)numPoints; i++) { if (H[i] == 0.0) { xyFreqResp.Graphs[0][i].y = -200.0; // dB } else { xyFreqResp.Graphs[0][i].y = 20.0 * log10(abs(H[i])); // dB } } } xyFreqResp.RefreshAll(); // wchar_t text[256]; _snwprintf_s(text, 256, _TRUNCATE, L"Error = %g", error); this->Text = text; } void RemezTest::sldLength_Hscroll(Win::Event& e) { tbxLength.IntValue = sldLength.Position; UpdateGraphs(); } void RemezTest::radioLowPass_Click(Win::Event& e) { UpdateGraphs(); } void RemezTest::radioHighPass_Click(Win::Event& e) { UpdateGraphs(); } void RemezTest::radioBandPass_Click(Win::Event& e) { UpdateGraphs(); } void RemezTest::radioBandStop_Click(Win::Event& e) { UpdateGraphs(); } void RemezTest::radioHilbert_Click(Win::Event& e) { UpdateGraphs(); } void RemezTest::radioDifferentiator_Click(Win::Event& e) { UpdateGraphs(); } |






Kaiser Window |
| The Kaiser Window can be used to design digital Filters. It has two parameters, the length of the filter and beta. La ventana de Kaiser puede ser usada para diseñar Filtros digitales. Este tiene dos parámetros, la longitud del filtro y la beta. |
| Problem 2 |
| Create a project to test the Kaiser Window method to design a digital filter; your project must be called KaiserTest. Cree un proyecto para probar el método de la ventana de Kaiser para diseñar un filtro digital; su proyecto debe ser llamado KaiserTest. |
| Solution A |
| Create a Wintempla Dialog Application. Using Wintempla create the GUI shown below. After inserting the slider for the length of the filter, double click the control and mark the HSCROLL event. Insert another slider for beta. Cree una aplicación de diálogo de Wintempla. Usando Wintempla cree la GUI mostrada debajo. Después de insertar el slider para longitud del filtro, haga clic doble en el control y marque el evento de HSCROLL. Inserte otro slider para beta. |

| Solution B |
| Edit the KaiserTest.h file as shown. Edite el archivo KaiserTest.h como se muestra. |
| KaiserTest.h |
| #pragma once //______________________________________ KaiserTest.h #include "resource.h" class KaiserTest: public Win::Dialog { public: KaiserTest() { } ~KaiserTest() { } Math::FIRFilter filter; const size_t numPoints = 2048; valarray<double> freqRad; void UpdateGraphs(); protected: . . . }; |
| Solution C |
| Edit the KaiserTest.cpp file as shown. Edite el archivo KaiserTest.cpp como se muestra. |
| KaiserTest.Cpp |
| . . . void KaiserTest::Window_Open(Win::Event& e) { //________________________________________________________ sldLength sldLength.SetRange(2, 200); sldLength.Position = 10; tbxLength.IntValue = 10; //________________________________________________________ sldBeta sldBeta.SetRange(0, 3000); sldBeta.Position = 100; tbxBeta.DoubleValue = 1.0; //________________________________________________________ xyFreqResp xyFreqResp.CaptionX = L"Frequency"; xyFreqResp.CaptionY = L"Amplitude dB"; xyFreqResp.MinX= 0.0; // radians xyFreqResp.MaxX = M_PI; // radians xyFreqResp.MinY = -100.0; // dB xyFreqResp.MaxY = 0.0; // dB xyFreqResp.DivisionCountY = 5; xyFreqResp.Graphs.Add(numPoints); freqRad.resize(numPoints); const double deltaFreq = M_PI / (numPoints - 1); for (size_t i = 0; i < numPoints; i++) { freqRad[i]= i * deltaFreq; xyFreqResp.Graphs[0][i].x = i* deltaFreq; xyFreqResp.Graphs[0][i].y = -200.0; } //________________________________________________________ xyImpulseResponse xyImpulseResponse.CaptionX = L"n"; xyImpulseResponse.CaptionY = L"h[n]"; xyImpulseResponse.MinX= -1.0; xyImpulseResponse.MaxX= 6.28; xyImpulseResponse.MinY= -0.2; xyImpulseResponse.MaxY= 0.8; xyImpulseResponse.DivisionCountY = 5; xyImpulseResponse.Graphs.Add(); xyImpulseResponse.Graphs[0].Type = Win::Graph::impulse; radioKaiser.Checked = true; // UpdateGraphs(); } void KaiserTest::sldLength_Hscroll(Win::Event& e) { tbxLength.IntValue = sldLength.Position; UpdateGraphs(); } void KaiserTest::sldBeta_Hscroll(Win::Event& e) { tbxBeta.DoubleValue = sldBeta.Position/100.0; UpdateGraphs(); } void KaiserTest::UpdateGraphs() { Win::HourGlassCursor hgc(true); const int filterLength = tbxLength.IntValue; double beta = tbxBeta.DoubleValue; if (radioBartlett.Checked) beta = BARTLETT_WINDOW; else if (radioHanning.Checked) beta = HANNING_WINDOW; else if (radioHamming.Checked) beta = HAMMING_WINDOW; else if (radioBlackman.Checked) beta = BLACKMAN_WINDOW; // valarray<double> h; filter.CreateLowPass(beta, filterLength, 0.5 * M_PI); filter.GetImpulseResponse(h); //________________________________________________________ xyImpulseResponse const size_t len = h.size(); size_t i; xyImpulseResponse.Graphs[0].SetPointCount(len); for(i = 0; i < len; i++) { xyImpulseResponse.Graphs[0][i].x = i; xyImpulseResponse.Graphs[0][i].y = h[i]; } xyImpulseResponse.MaxX= len; xyImpulseResponse.RefreshAll(); //________________________________________________________ xyFreqResp valarray<complex<double> > H; // H(exp(jw)) filter.GetFrequencyResponse(freqRad, H); for(i = 0; i < numPoints; i++) { if (abs(H[i]) == 0.0) { xyFreqResp.Graphs[0][i].y = -200.0; // dB } else { xyFreqResp.Graphs[0][i].y = 20.0 * log10(abs(H[i])); // dB } } xyFreqResp.RefreshAll(); } void KaiserTest::radioKaiser_Click(Win::Event& e) { UpdateGraphs(); } void KaiserTest::radioBartlett_Click(Win::Event& e) { UpdateGraphs(); } void KaiserTest::radioHanning_Click(Win::Event& e) { UpdateGraphs(); } void KaiserTest::radioHamming_Click(Win::Event& e) { UpdateGraphs(); } void KaiserTest::radioBlackman_Click(Win::Event& e) { UpdateGraphs(); } |





| Problem 3 |
| Create a Wintempla dialog application called FilterPlay to filter (in real time) a music wave file. After creating the project open the stdafx.h file and remove the comments from the line #define WIN_DAC_ADC_SUPPORT. Cree una aplicación de diálogo de Wintempla llamada FilterPlay para filtrar (en tiempo real) un archivo de música wave. Después de crear el proyecto abra el archivo stdafx.h y remueva los comentarios de la línea #define WIN_DAC_ADC_SUPPORT. |
| Solution A |
Open Wintempla to edit the GUI. Using the Show All Controls in Toolbox from the toolbar insert a DAC control as shown below (on the events tabs, be sure all events are unselected). Insert two labels, two textboxes, four radio buttons, two sliders (with the Hscroll event), a button, a XyChart and drop down list.Abra Wintempla y edite la GUI. Usando the Show All Controls in Toolbox desde la barra de herramientas inserta un control DAC como se muestra debajo (en la pestaña de eventos, asegúrate de que todos los eventos estén deseleccionado). Inserta dos etiquetas, dos cajas de texto, cuatro radio buttons, dos sliders (con el evento HScroll), un botón, una XyChart y una lista desplegable. |

| Solution B |
| Edit the FilterPlay.h file and the FilterPlay.cpp file to implement the three functions of the Mm::IAudioOut interface (Observe the the FilterPlay class is derived from Mm::IAudioOut). Remember that an interface is used to pass a set of functions to another function or another object. Edite los archivos FilterPlay.h y FilterPlay.cpp para implementar las tres funciones de la interface Mm::IAudioOut (Observa que la clase FilterPlay se deriva de Mm::IAudioOut). Recuerde que una interface es usada para pasar un conjunto de funciones a otra función u objeto. |
| FilterPlay.h |
| #pragma once //______________________________________ FilterPlay.h #include "Resource.h" class FilterPlay: public Win::Dialog, public Mm::IAudioOut { public: FilterPlay() { } ~FilterPlay() { } const size_t numPoints = 2048; valarray<double> freqRad; Math::FIRFilter fir; const double sampFreqHz = 44100.0; Mm::WaveFile waveFile; void UpdateFilter(); //______________________________________________________________ Mm::IAudioOut void AudioOutStarted(unsigned int sampFreqHz, unsigned int numChannels, unsigned int bitsResolution); void AudioOutData(unsigned int sampFreqHz, unsigned int numChannels, unsigned int bitsResolution, WAVEHDR* waveHdr); void AudioOutStopped(); protected: . . . }; |
| FilterPlay.cpp |
| . . . void FilterPlay::Window_Open(Win::Event& e) { //________________________________________________________ sldFc sldFc.SetRange(1, 15000); sldFc.Position = 6900; tbxFc.IntValue = 6900; //________________________________________________________ sldBeta sldBeta.SetRange(1, 1000); sldBeta.Position = 434; tbxBeta.DoubleValue = 4.34; //________________________________________________________ sldLength sldLength.SetRange(10, 100); sldLength.Position = 52; tbxLength.IntValue = 52; //________________________________________________________ xyFreqResp xyFreqResp.CaptionX = L"Frequency (Hz)"; xyFreqResp.CaptionY = L"|H[f]| dB"; xyFreqResp.MinX = 0.0; xyFreqResp.MaxX = sampFreqHz / 2.0; xyFreqResp.MinY = -90.0; // dB xyFreqResp.MaxY = 10.0; // dB xyFreqResp.DivisionCountX = 11; xyFreqResp.DivisionCountY = 5; xyFreqResp.ColorMode = WIN_COLOR_MODE_DARK; xyFreqResp.Graphs.Add((int)numPoints); freqRad.resize(numPoints); const double deltaFreq = M_PI / (numPoints - 1); for (int i = 0; i < (int)numPoints; i++) { freqRad[i] = i * deltaFreq; xyFreqResp.Graphs[0][i].x = (i * deltaFreq * sampFreqHz) / (2.0 * M_PI); xyFreqResp.Graphs[0][i].y = -200.0; } xyFreqResp.Graphs[0].Color = RGB(0, 255, 0); xyFreqResp.TextColor = RGB(255, 255, 255); xyFreqResp.RefreshAll(); //________________________________________________________ ddDevice const int count = ::waveOutGetNumDevs(); WAVEOUTCAPS woc; const int wsize = sizeof(WAVEOUTCAPS); for (int i = 0; i < count; i++) { if (::waveOutGetDevCaps(i, &woc, wsize) == MMSYSERR_NOERROR) { ddDevice.Items.Add(woc.szPname, i); } } ddDevice.SelectedIndex = 0; //________________________________________________________ xyImpulseResponse xyImpulseResponse.CaptionX = L"n"; xyImpulseResponse.CaptionY = L"h[n]"; xyImpulseResponse.MinX = -1.0; xyImpulseResponse.MaxX = 6.28; xyImpulseResponse.MinY = -0.8; xyImpulseResponse.MaxY = 0.8; xyImpulseResponse.DivisionCountY = 4; xyImpulseResponse.Graphs.Add(); xyImpulseResponse.Graphs[0].Type = Win::Graph::impulse; xyImpulseResponse.Graphs[0].Color = RGB(0, 255, 0); xyImpulseResponse.SetColorMode(WIN_COLOR_MODE_DARK); xyImpulseResponse.TextColor = RGB(255, 255, 255); // this->btPlay.Enabled = true; this->btStop.Enabled = false; radioLowpass.Checked = true; UpdateFilter(); } void FilterPlay::sldFc_Hscroll(Win::Event& e) { tbxFc.IntValue = sldFc.Position; UpdateFilter(); } void FilterPlay::sldBeta_Hscroll(Win::Event& e) { tbxBeta.DoubleValue = sldBeta.Position / 100.0; UpdateFilter(); } void FilterPlay::sldLength_Hscroll(Win::Event& e) { tbxLength.IntValue = sldLength.Position; UpdateFilter(); } void FilterPlay::UpdateFilter() { const int length = tbxLength.IntValue; const double nyquist = sampFreqHz / 2.0; const double wc = M_PI * tbxFc.IntValue / nyquist; const double beta = tbxBeta.DoubleValue; // if (radioLowpass.Checked) { filter.CreateLowPass(beta, length, wc); } else if (radioBandpass.Checked) { filter.CreateBandPass(beta, length, wc, wc + 0.5); } else if (radioBandstop.Checked) { filter.CreateBandStop(beta, length, wc, wc + 0.5); } else if (radioHighpass.Checked) { filter.CreateHighPass(beta, length, wc); } else if (radioHilbert.Checked) { filter.CreateHilbertTransform(beta, length); } else if (radioDifferentiator.Checked) { filter.CreateDifferentiator(beta, length); } if (filter.IsSymmetric()) xyImpulseResponse.Graphs[0].Caption = L"SYMMETRIC"; else if (filter.IsAntisymmetric()) xyImpulseResponse.Graphs[0].Caption = L"ANTISYMMETRIC"; else xyImpulseResponse.Graphs[0].Caption = L"Impulse Response"; valarray<double> h; filter.GetImpulseResponse(h); //________________________________________________________ xyImpulseResponse const int len = (int)h.size(); int i; xyImpulseResponse.Graphs[0].SetPointCount(len); for (i = 0; i < len; i++) { xyImpulseResponse.Graphs[0][i].x = i; xyImpulseResponse.Graphs[0][i].y = h[i]; } xyImpulseResponse.MaxX = len; xyImpulseResponse.RefreshAll(); //________________________________________________________ xyFreqResp valarray<complex<double> > H; // H(exp(jw)) filter.GetFrequencyResponse(freqRad, H); for (int i = 0; i < numPoints; i++) { if (abs(H[i]) == 0.0) { xyFreqResp.Graphs[0][i].y = -200.0; // dB } else { xyFreqResp.Graphs[0][i].y = 20.0 * log10(abs(H[i])); // dB } } xyFreqResp.RefreshAll(); } void FilterPlay::btStop_Click(Win::Event& e) { dacOutput.Stop(); } void FilterPlay::btPlay_Click(Win::Event& e) { //________________________________________________________ 1. Prompt to the user to get the filename Win::FileDlg dlg; dlg.Clear(); dlg.SetFilter(L"Wave files (*.wav)\0*.wav\0\0", 0, L"wav"); if (dlg.BeginDialog(hWnd, L"Open", false) != TRUE) return; //________________________________________________________ 2. Get the Device ID LPARAM deviceID = WAVE_MAPPER; ddDevice.GetSelectedData(deviceID); //________________________________________________________ 3. Open the Wave File const wchar_t* error = waveFile.OpenForReading(dlg.GetFileNameFullPath()); if (error != NULL) { this->MessageBox(error, L"FilePlayer", MB_OK | MB_ICONERROR); return; } //________________________________________________________ 4. Start the DAC const unsigned int numChannels = waveFile.GetNumChannels(); const unsigned int bitsResolution = waveFile.GetBitsResolution(); const unsigned int numBytes = 4096 * numChannels * bitsResolution / 8; error = dacOutput.Start((unsigned int)deviceID, waveFile.GetSampFreqHz(), numChannels, bitsResolution, numBytes, this); if (error != NULL) { this->MessageBox(error, L"FilterPlay", MB_OK | MB_ICONERROR); return; } } void FilterPlay::AudioOutStarted(unsigned int sampFreqHz, unsigned int numbChannels, unsigned int bitsResolution) { btPlay.Enabled = false; btStop.Enabled = true; EnableCloseButton(false); } void FilterPlay::AudioOutData(unsigned int sampFreqHz, unsigned int numbChannels, unsigned int bitsResolution, WAVEHDR* waveHdr) { waveHdr->dwBytesRecorded = waveFile.ReadData(waveHdr->lpData, waveHdr->dwBufferLength); Sys::Sample16* samples = (Sys::Sample16*)waveHdr->lpData; const size_t numSamples = waveHdr->dwBytesRecorded / 4; filter.ComputeOutput(samples, numSamples); } void FilterPlay::AudioOutStopped() { btPlay.Enabled = true; btStop.Enabled = false; waveFile.Close(); EnableCloseButton(true); } void FilterPlay::radioLowpass_Click(Win::Event& e) { UpdateFilter(); } void FilterPlay::radioBandpass_Click(Win::Event& e) { UpdateFilter(); } void FilterPlay::radioBandstop_Click(Win::Event& e) { UpdateFilter(); } void FilterPlay::radioHighpass_Click(Win::Event& e) { UpdateFilter(); } void FilterPlay::radioHilbert_Click(Win::Event& e) { UpdateFilter(); } void FilterPlay::radioDifferentiator_Click(Win::Event& e) { UpdateFilter(); } |
| Solution C |
| Run the program and click the Play button. Select a wave file with two channels, 44100 Hz and 16 bits. Ejecute el programa y haga clic en el botón de Play. Seleccione un archivo Wave con dos canales, 44100 Hz y 16 bits. |







Frequency Sampling |
| It is a method to design digital FIR filters with a custom frequency response. Este es un método para diseñar FIR filtros digitales con una respuesta en frecuencia particular. |
| Problem 4 |
| Create a Wintempla Dialog Application called Loudfir to implement a lowpass filter. Using Wintempla create the GUI shown below. Cree una aplicación de diálogo de Wintempla llamada Loudfir para implementar un filtro pasa bajas. Usando Wintempla cree la GUI mostrada debajo. |

| Solution A |
| Edit the Loudfir.h file as shown. Edite el archivo Loudfir.h como se muestra. |
| Loudfir.h |
| #pragma once //______________________________________ Loudfir.h #include "Resource.h" class Loudfir: public Win::Dialog { public: Loudfir() { } ~Loudfir() { } Math::FIRFilter filter; const double sampFreqHz = 44100.0; void Desired(); void ImpulseResponse(); void FrequencyResponse(); protected: . . . }; |
| Solution B |
| Edit the Loudfir.cpp file as shown. Edite el archivo Loudfir.cpp como se muestra. |
| Loudfir.Cpp |
| . . . void Loudfir::Window_Open(Win::Event& e) { Desired(); ImpulseResponse(); FrequencyResponse(); } void Loudfir::Desired() { //_______________________________________________ Example 1. DSP Proakis Example 8.2.1, page 632 constexpr double delta = (2.0 * M_PI) / 15.0; vector<Math::FIRFilter::Sample> sample = { {0, 0}, {delta, 0}, {2 * delta, 0}, {3 * delta, 0}, {4 * delta, 20.0 * log10(0.4)}, {5 * delta, -200.0}, {6 * delta, -200.0}, {7 * delta, -200.0} }; //_______________________________________________ Example 2. DSP Proakis Example 8.2.2, page 634 //constexpr double delta = (2.0 * M_PI) / 32.0; //vector<Math::FIRFilter::Sample> sample = { {0, 0}, {delta, 0}, {2 * delta, 0}, {3 * delta, 0}, // {4 * delta, 0}, {5 * delta, 0}, {6 * delta, 20.0 * log10(0.3789795)}, {7 * delta, -200.0}, {8 * delta, -200.0}, // {9 * delta, -200.0}, {10 * delta, -200.0}, {11 * delta, -200.0}, {12 * delta, -200.0}, // {13 * delta, -200.0}, {14 * delta, -200.0}, {15 * delta, -200.0} }; int i; xyDesired.CaptionX = L"Frequency (Hz)"; xyDesired.CaptionY = L"Amplitude (dB)"; xyDesired.MinX = 10.0; // Hz xyDesired.MaxX = 100000.0; // Hz xyDesired.MinY = -60.0; // dB xyDesired.MaxY = 0.0; // dB xyDesired.SetLogScaleX(true); xyDesired.DivisionCountX = 4; xyDesired.DivisionCountY = 6; xyDesired.Graphs.Add((int)sample.size()); for (i = 0; i < (int)sample.size(); i++) { xyDesired.Graphs[0][i].x = (sample[i].freqRad * sampFreqHz) / (2.0 * M_PI); // From rads to Hz xyDesired.Graphs[0][i].y = sample[i].gain_dB; } xyDesired.ColorMode = WIN_COLOR_MODE_DARK; xyDesired.Graphs[0].Color = RGB(0, 200, 0); xyDesired.Graphs[0].Caption = L"Desired frequency response"; xyDesired.TextColor = RGB(255, 255, 255); xyDesired.RefreshAll(); filter.CreateFromFreqSamples(sample); } void Loudfir::ImpulseResponse() { valarray<double> h; filter.GetImpulseResponse(h); const int len = (int)h.size(); xyImpResp.CaptionX = L"Axis X"; xyImpResp.CaptionY = L"h[n]"; xyImpResp.MinX = 0.0; xyImpResp.MaxX = len; xyImpResp.MinY = -1.0; xyImpResp.MaxY = 1.0; xyImpResp.Graphs.Add(len); for (int i = 0; i < len; i++) { xyImpResp.Graphs[0][i].x = i; xyImpResp.Graphs[0][i].y = h[i]; } xyImpResp.Graphs[0].Color = RGB(200, 200, 0); xyImpResp.Graphs[0].Type = Win::Graph::impulse; xyImpResp.Graphs[0].Caption = L"Impulse Response"; xyImpResp.ColorMode = WIN_COLOR_MODE_DARK; xyImpResp.TextColor = RGB(255, 255, 255); xyImpResp.RefreshAll(); } void Loudfir::FrequencyResponse() { const int numFreq = 1024; const double deltaFreqRad = M_PI / (numFreq - 1.0); int i = 0; valarray<double> freqRad; freqRad.resize(numFreq); for (i = 0; i < numFreq; i++) freqRad[i] = i * deltaFreqRad; valarray<complex<double> > H; // H(exp(jw)) filter.GetFrequencyResponse(freqRad, H); xyFreqResp.CaptionX = L"Frequency (Hz)"; xyFreqResp.CaptionY = L"Amplitude (dB)"; xyFreqResp.MinX = 10.0; // Hz xyFreqResp.MaxX = 100000.0; // Hz xyFreqResp.MinY = -60.0; // dB xyFreqResp.MaxY = 0.0; // dB xyFreqResp.SetLogScaleX(true); xyFreqResp.DivisionCountX = 4; xyFreqResp.DivisionCountY = 6; xyFreqResp.Graphs.Add(numFreq); for (i = 0; i < numFreq; i++) { xyFreqResp.Graphs[0][i].x = (sampFreqHz * freqRad[i]) / (2.0 * M_PI); if (abs(H[i]) == 0.0) { xyFreqResp.Graphs[0][i].y = -200.0; // dB } else { xyFreqResp.Graphs[0][i].y = 20.0 * log10(abs(H[i])); // dB } } xyFreqResp.ColorMode = WIN_COLOR_MODE_DARK; xyFreqResp.Graphs[0].Color = RGB(0, 200, 0); xyFreqResp.Graphs[0].Caption = L"Frequency response"; xyFreqResp.TextColor = RGB(255, 255, 255); xyFreqResp.RefreshAll(); } |

